// $ANTLR 2.7.6 (2005-12-22): "resources/grammars/ParameterLabelParser.g" -> "ParameterLabelParser.java"$

package com.cea.papyrus.classdiagram.parsers.antlr;

import org.eclipse.uml2.uml.*;
import com.cea.papyrus.umlutils.Parameter;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Collection;
import java.util.Vector;

import com.cea.papyrus.classdiagram.parsers.texteditor.parameterlabel.IContext;
import com.cea.papyrus.classdiagram.parsers.util.Assert;

import antlr.TokenBuffer;
import antlr.TokenStreamException;
import antlr.TokenStreamIOException;
import antlr.ANTLRException;
import antlr.LLkParser;
import antlr.Token;
import antlr.TokenStream;
import antlr.RecognitionException;
import antlr.NoViableAltException;
import antlr.MismatchedTokenException;
import antlr.SemanticException;
import antlr.ParserSharedInputState;
import antlr.collections.impl.BitSet;

public class ParameterLabelParser extends antlr.LLkParser       implements ParameterLabelParserTokenTypes
 {

	public ParameterLabelParser(TokenStream lexer, com.cea.papyrus.umlutils.Parameter parameter) {
		this(lexer);
		this.parameter = parameter.getUml2Parameter();	
		this.contextPackage = new com.cea.papyrus.umlutils.Package(this.parameter.getNearestPackage());
		this.modifiersUsed = new HashMap<String, Boolean>();
		modifiersUsed.put("ordered", false);	
		modifiersUsed.put("unique", false);	
		modifiersUsed.put("nonunique", false);
	}
	
	/**
	 * Validation state (true = validation : does not modify the parameter
	 */
	private boolean isValidation = false;
	
	/**
	 * @return the isValidation boolean
	 */
	public boolean isValidation() {
		return isValidation;
	}

	/**
	 * @param isValidation the isValidation to set (true -> do not modify the parameter)
	 */
	public void setValidation(boolean isValidation) {
		this.isValidation = isValidation;
	}
	
	/**
	 * Modified Parameter 
	 */
	private org.eclipse.uml2.uml.Parameter parameter;
	
	/**
	 * @return the parameter
	 */
	public org.eclipse.uml2.uml.Parameter getParameter() {
		return parameter;
	}

	/**
	 * @param parameter the parameter to set
	 */
	public void setParameter(org.eclipse.uml2.uml.Parameter parameter) {
		this.parameter = parameter;
	}
    	
    /** debug mode */
    protected final boolean debugMode = false;  	
    	
    /**
     * Debug method (~System.out.println)
     */
    private void debug(Object debug) {
    	if(debugMode) {
    		System.out.println(debug);	
    	}	
    }
    
    /**
     * Error method (~System.err.println)
     */
    private void error(Object debug) {
    	if(debugMode) {
    		System.err.println(debug);	
    	}	
    }
    
    /**
     * Context (for completion processor)
     */
    private int context = IContext.DEFAULT;
    
    /**
	 * @return the context
	 */
	public int getContext() {
		return context;
	}

	/**
	 * @param context the context to set
	 */
	public void setContext(int context) {
		this.context = context;
	}
    
    // all possible modified elements on parameter (with default values : necessary ?!)
  	private String name;
    private ParameterDirectionKind direction;
   	private Type type;
   	private String defaultValue = null;
   	private int lowerMultiplicity = 1;	// default multiplicity = [1..1]
    private int upperMultiplicity = 1;	// default multiplicity = [1..1]
	private boolean isUnique = true;	// default value = true
  	private boolean isOrdered = false;	// default value = false     

    private com.cea.papyrus.umlutils.Package contextPackage = null;
    
	/**
	 * Apply values to the parameter. <BR> 
	 * Modifications can not be applied directly. The parser must wait the end, 
	 * until it reaches the end of the label. If the end is reached without any error,
	 * new values can be applied to the target parameter.
	 */
	private void applyValues() {
		if(!isValidation){
			debug("\nvalues applied :");
			debug("+  name: "+name);
			debug("+  direction: "+direction);
			debug("+  type: "+type);
			debug("+  lower Multiplicity: "+lowerMultiplicity);
			debug("+  upper Multiplicity: "+upperMultiplicity);
			debug("+  default Value: "+defaultValue);
			debug("+  Property modifiers");
			debug("+    isUnique: "+isUnique);
			debug("+    isOrdered: "+isOrdered);
			
			parameter.setName(name);
			parameter.setDirection(direction);
			parameter.setType(type);
			parameter.setLower(lowerMultiplicity);
			parameter.setUpper(upperMultiplicity);
			parameter.setDefault(defaultValue);
			parameter.setIsUnique(isUnique);
			parameter.setIsOrdered(isOrdered);
		} 
	}
	
	
	// vector that keeps modifiers already used (used for completion)
	public Map<String, Boolean> modifiersUsed; 
	
	/**
	 * @return the modifiersUsed
	 */
	public Map<String, Boolean> getModifiersUsed() {
		return modifiersUsed;
	}

	/**
	 * @param modifiersUsed the modifiersUsed to set
	 */
	public void setModifiersUsed(Map<String, Boolean> modifiersUsed) {
		this.modifiersUsed = modifiersUsed;
	}

protected ParameterLabelParser(TokenBuffer tokenBuf, int k) {
  super(tokenBuf,k);
  tokenNames = _tokenNames;
}

public ParameterLabelParser(TokenBuffer tokenBuf) {
  this(tokenBuf,2);
}

protected ParameterLabelParser(TokenStream lexer, int k) {
  super(lexer,k);
  tokenNames = _tokenNames;
}

public ParameterLabelParser(TokenStream lexer) {
  this(lexer,2);
}

public ParameterLabelParser(ParserSharedInputState state) {
  super(state,2);
  tokenNames = _tokenNames;
}

	public final void label() throws RecognitionException, TokenStreamException {
		
		
		{
		_loop3:
		do {
			if ((LA(1)==WS)) {
				match(WS);
			}
			else {
				break _loop3;
			}
			
		} while (true);
		}
		{
		switch ( LA(1)) {
		case LITERAL_in:
		case LITERAL_out:
		case LITERAL_inout:
		case LITERAL_return:
		{
			direction();
			context = IContext.DIRECTION;
			{
			_loop6:
			do {
				if ((LA(1)==WS)) {
					match(WS);
				}
				else {
					break _loop6;
				}
				
			} while (true);
			}
			break;
		}
		case IDENTIFIER:
		{
			break;
		}
		default:
		{
			throw new NoViableAltException(LT(1), getFilename());
		}
		}
		}
		parameter_name();
		context = IContext.NAME;
		{
		switch ( LA(1)) {
		case WS:
		{
			{
			{
			int _cnt10=0;
			_loop10:
			do {
				if ((LA(1)==WS)) {
					match(WS);
				}
				else {
					if ( _cnt10>=1 ) { break _loop10; } else {throw new NoViableAltException(LT(1), getFilename());}
				}
				
				_cnt10++;
			} while (true);
			}
			match(COLON);
			}
			break;
		}
		case COLON:
		{
			match(COLON);
			break;
		}
		default:
		{
			throw new NoViableAltException(LT(1), getFilename());
		}
		}
		}
		context = IContext.AFTER_COLON;
		parameter_type();
		context = IContext.PARAMETER_TYPE;
		{
		_loop12:
		do {
			if ((LA(1)==WS)) {
				match(WS);
			}
			else {
				break _loop12;
			}
			
		} while (true);
		}
		{
		switch ( LA(1)) {
		case LSQUARE:
		{
			multiplicity();
			context = IContext.MULTIPLICITY;
			{
			_loop15:
			do {
				if ((LA(1)==WS)) {
					match(WS);
				}
				else {
					break _loop15;
				}
				
			} while (true);
			}
			break;
		}
		case EOF:
		case EQ:
		case LCURLY:
		{
			break;
		}
		default:
		{
			throw new NoViableAltException(LT(1), getFilename());
		}
		}
		}
		{
		switch ( LA(1)) {
		case EQ:
		{
			default_value();
			context = IContext.DEFAULT_VALUE;
			break;
		}
		case EOF:
		case LCURLY:
		{
			break;
		}
		default:
		{
			throw new NoViableAltException(LT(1), getFilename());
		}
		}
		}
		{
		switch ( LA(1)) {
		case LCURLY:
		{
			parameter_modifiers();
			context = IContext.PARAMETER_MODIFIERS;
			break;
		}
		case EOF:
		{
			break;
		}
		default:
		{
			throw new NoViableAltException(LT(1), getFilename());
		}
		}
		}
		
				applyValues();
			
	}
	
	public final void direction() throws RecognitionException, TokenStreamException {
		
		
		{
		switch ( LA(1)) {
		case LITERAL_in:
		{
			match(LITERAL_in);
			direction = ParameterDirectionKind.IN_LITERAL;
			break;
		}
		case LITERAL_out:
		{
			match(LITERAL_out);
			direction = ParameterDirectionKind.OUT_LITERAL;
			break;
		}
		case LITERAL_inout:
		{
			match(LITERAL_inout);
			direction = ParameterDirectionKind.INOUT_LITERAL;
			break;
		}
		case LITERAL_return:
		{
			match(LITERAL_return);
			direction = ParameterDirectionKind.RETURN_LITERAL;
			break;
		}
		default:
		{
			throw new NoViableAltException(LT(1), getFilename());
		}
		}
		}
	}
	
	public final void parameter_name() throws RecognitionException, TokenStreamException {
		
		Token  id = null;
		
		id = LT(1);
		match(IDENTIFIER);
		
				name = id.getText();
			
	}
	
	public final void parameter_type() throws RecognitionException, TokenStreamException {
		
		
		{
		_loop23:
		do {
			if ((LA(1)==WS)) {
				match(WS);
			}
			else {
				break _loop23;
			}
			
		} while (true);
		}
		{
		switch ( LA(1)) {
		case IDENTIFIER:
		{
			type();
			break;
		}
		case LT:
		{
			match(LT);
			match(LITERAL_Undefined);
			match(GT);
			break;
		}
		default:
		{
			throw new NoViableAltException(LT(1), getFilename());
		}
		}
		}
	}
	
	public final void multiplicity() throws RecognitionException, TokenStreamException {
		
		
		match(LSQUARE);
		context = IContext.IN_MULTIPLICITY;
		{
		if ((LA(1)==INTEGER) && (LA(2)==POINT_POINT)) {
			lower_multiplicity();
			match(POINT_POINT);
			upper_multiplicity();
			
						if(lowerMultiplicity > upperMultiplicity && upperMultiplicity != -1) {
							throw new RecognitionException("Lower bound ("+lowerMultiplicity+") is greater than upper bound ("+upperMultiplicity+")");
						}
					
		}
		else if ((LA(1)==INTEGER||LA(1)==STAR) && (LA(2)==RSQUARE)) {
			upper_multiplicity();
			
						if(upperMultiplicity == -1) {
							lowerMultiplicity = 0;
						} else {
							lowerMultiplicity = upperMultiplicity;
						}
					
		}
		else {
			throw new NoViableAltException(LT(1), getFilename());
		}
		
		}
		match(RSQUARE);
	}
	
	public final void default_value() throws RecognitionException, TokenStreamException {
		
		
		match(EQ);
		defaultValue=expression();
		
				// remove spaces at the begining 
				defaultValue = defaultValue.trim();
			
	}
	
	public final void parameter_modifiers() throws RecognitionException, TokenStreamException {
		
		
		match(LCURLY);
		context = IContext.PARAMETER_MODIFIER;
		parameter_modifier();
		{
		_loop39:
		do {
			if ((LA(1)==COMMA)) {
				context = IContext.PARAMETER_MODIFIER;
				match(COMMA);
				parameter_modifier();
			}
			else {
				break _loop39;
			}
			
		} while (true);
		}
		match(RCURLY);
	}
	
	public final void type() throws RecognitionException, TokenStreamException {
		
		Token  id = null;
		
		id = LT(1);
		match(IDENTIFIER);
		
				String typeName = id.getText();
				com.cea.papyrus.umlutils.Type utilType = contextPackage.findTypeByName(typeName);
				if(utilType != null) {
					type = utilType.getUml2Type();
				} else {
					throw new RecognitionException("Type "+typeName+" not found for parameter "+parameter.getName());
				}
			
	}
	
	public final void lower_multiplicity() throws RecognitionException, TokenStreamException {
		
		Token  in = null;
		
		in = LT(1);
		match(INTEGER);
		
				lowerMultiplicity = Integer.parseInt(in.getText());
			
	}
	
	public final void upper_multiplicity() throws RecognitionException, TokenStreamException {
		
		
		upperMultiplicity=unlimited_natural();
	}
	
	public final int  unlimited_natural() throws RecognitionException, TokenStreamException {
		int value = 0 ;
		
		Token  in = null;
		
		{
		switch ( LA(1)) {
		case STAR:
		{
			match(STAR);
			value = -1;
			break;
		}
		case INTEGER:
		{
			in = LT(1);
			match(INTEGER);
			value = Integer.parseInt(in.getText());
			break;
		}
		default:
		{
			throw new NoViableAltException(LT(1), getFilename());
		}
		}
		}
		return value;
	}
	
	public final String  expression() throws RecognitionException, TokenStreamException {
		String value  = "";
		
		Token  id = null;
		
				StringBuffer buffer = new StringBuffer();
			
		
		{
		int _cnt36=0;
		_loop36:
		do {
			if ((_tokenSet_0.member(LA(1)))) {
				{
				id = LT(1);
				match(_tokenSet_0);
				}
				
							buffer.append(id.getText());
						
			}
			else {
				if ( _cnt36>=1 ) { break _loop36; } else {throw new NoViableAltException(LT(1), getFilename());}
			}
			
			_cnt36++;
		} while (true);
		}
		
				value = buffer.toString();
			
		return value;
	}
	
	public final void parameter_modifier() throws RecognitionException, TokenStreamException {
		
		
		{
		_loop42:
		do {
			if ((LA(1)==WS)) {
				match(WS);
			}
			else {
				break _loop42;
			}
			
		} while (true);
		}
		{
		switch ( LA(1)) {
		case COMMA:
		case RCURLY:
		{
			break;
		}
		case LITERAL_ordered:
		{
			match(LITERAL_ordered);
			isOrdered = true; modifiersUsed.put("ordered", true);	
			break;
		}
		case LITERAL_unique:
		{
			match(LITERAL_unique);
			isUnique = true; modifiersUsed.put("unique", true); modifiersUsed.put("nonunique", true);
			break;
		}
		case LITERAL_nonunique:
		{
			match(LITERAL_nonunique);
			isUnique = false; modifiersUsed.put("unique", true); modifiersUsed.put("nonunique", true);
			break;
		}
		default:
		{
			throw new NoViableAltException(LT(1), getFilename());
		}
		}
		}
	}
	
	
	public static final String[] _tokenNames = {
		"<0>",
		"EOF",
		"<2>",
		"NULL_TREE_LOOKAHEAD",
		"WS",
		"COLON",
		"\"in\"",
		"\"out\"",
		"\"inout\"",
		"\"return\"",
		"IDENTIFIER",
		"LT",
		"\"Undefined\"",
		"GT",
		"LSQUARE",
		"POINT_POINT",
		"RSQUARE",
		"INTEGER",
		"STAR",
		"EQ",
		"LCURLY",
		"COMMA",
		"RCURLY",
		"\"ordered\"",
		"\"unique\"",
		"\"nonunique\"",
		"NL",
		"QUESTION_MARK",
		"LNOT",
		"DOUBLE_QUOTE",
		"SINGLE_QUOTE",
		"LPAREN",
		"RPAREN",
		"DOUBLE_LCURLY",
		"DOUBLE_RCURLY",
		"LOGICAL_AND",
		"DOUBLE_LOGICAL_AND",
		"PIPE",
		"DOUBLE_PIPE",
		"POINT",
		"SEMI",
		"SHARP",
		"TILDE",
		"DOUBLE_COLON",
		"RULE_ASSIGN",
		"ARROW",
		"DIV",
		"PLUS",
		"MINUS",
		"ISEQ",
		"ISNE",
		"DOUBLE_LT",
		"LE",
		"DOUBLE_GT",
		"GE",
		"INCR",
		"DECR",
		"CALLOPERATION",
		"DIGIT",
		"ALPHA",
		"UNDERSCORE",
		"REAL",
		"REAL_OR_INT"
	};
	
	private static final long[] mk_tokenSet_0() {
		long[] data = { 9223372036853727216L, 0L, 0L, 0L};
		return data;
	}
	public static final BitSet _tokenSet_0 = new BitSet(mk_tokenSet_0());
	
	}
